package xyz.xuminghai.javafx_learn.animation;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.SVGPath;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
 * 2023/8/12 16:57 星期六<br/>
 * AnimationTimer类允许创建一个计时器，该计时器在每个帧处于活动状态时都会被调用。
 * 扩展类必须重写将在每个帧中调用的方法handle(long) 。 start()和stop()方法允许启动和停止计时器。
 *
 * @author xuMingHai
 */
public class AnimationTimerApp extends Application {

    private final BorderPane root = new BorderPane();

    private final Text fpsText = new Text("FPS:");

    private final Text frameRateText = new Text();

    private final Supplier<SVGPath> svgPathSupplier = () -> {
        SVGPath svgPath = new SVGPath();
        svgPath.setContent("""
                M15,0l-0.9,1.5v31.7l0.9,1.5l0.9-1.5V1.5L15,0z M15,7.5l-3.5-2.3V3.5L15,5.8V7.5z M15,11l-4.6-2.9V6.4L15,9.3
                    V11z M15,7.5l3.5-2.3V3.5L15,5.8V7.5z M15,11l4.6-2.9V6.4L15,9.3V11z M15,27.1l-3.5,2.3v1.7l3.5-2.3V27.1z M15,23.7l-4.6,2.9v1.7
                    l4.6-2.9V23.7z M15,27.1l3.5,2.3v1.7L15,28.8V27.1z M15,23.7l4.6,2.9v1.7L15,25.4V23.7z M0,26h1.7l27.4-15.8L30,8.7h-1.7L0.9,24.5
                    L0,26z M6.5,22.2l-0.3,4.1l-1.5,0.9L5,23.1L6.5,22.2z M9.5,20.5l-0.2,5.4l-1.5,0.9L8,21.4L9.5,20.5z M6.5,22.2l-3.7-1.8l-1.5,0.9
                    L5,23.1L6.5,22.2z M9.5,20.5L4.7,18l-1.5,0.9L8,21.4L9.5,20.5z M23.5,12.4l3.7,1.8l1.5-0.9L25,11.6L23.5,12.4z M20.5,14.2l4.8,2.6
                    l1.5-0.9L22,13.3L20.5,14.2z M23.5,12.4l0.3-4.1l1.5-0.9L25,11.6L23.5,12.4z M20.5,14.2l0.2-5.4l1.5-0.9L22,13.3L20.5,14.2z M30,26
                    h-1.7L0.9,10.2L0,8.7h1.7l27.4,15.8L30,26z M23.5,22.2l0.3,4.1l1.5,0.9L25,23.1L23.5,22.2z M20.5,20.5l0.2,5.4l1.5,0.9L22,21.4
                    L20.5,20.5z M23.5,22.2l3.7-1.8l1.5,0.9L25,23.1L23.5,22.2z M20.5,20.5l4.8-2.5l1.5,0.9L22,21.4L20.5,20.5z M6.5,12.4l-3.7,1.8
                    l-1.5-0.9L5,11.6L6.5,12.4z M9.5,14.2l-4.8,2.6l-1.5-0.9L8,13.3L9.5,14.2z M6.5,12.4L6.3,8.3L4.8,7.4L5,11.6L6.5,12.4z M9.5,14.2
                    L9.3,8.8L7.8,7.9L8,13.3L9.5,14.2z M15,22.8l-4.7-2.7v-5.4l4.7-2.7l4.7,2.7V20L15,22.8z M11.7,19.2l3.3,1.9l3.3-1.9v-3.7L15,13.6
                    l-3.3,1.9V19.2z
                """);
        svgPath.setFill(Color.SNOW);
        return svgPath;
    };

    private final int svgPathCapacity = 500;
    private final List<SVGPath> svgPathList = new ArrayList<>(svgPathCapacity);

    private final AnimationTimer animationTimer = new AnimationTimer() {

        // 上次计算FPS的时间戳
        private long lastTime;

        // 处理次数
        private int handleCount;

        @Override
        public void handle(long now) {
            // 计算FPS
            computeFPS(now);
            double rootHeight = root.getHeight();
            double width = root.getWidth() - 30.0;
            svgPathList.forEach(svgPath -> {
                double translateY = svgPath.getTranslateY();
                // 重新设置初始值
                if (translateY >= rootHeight) {
                    svgPath.setRotate(0.0);
                    svgPath.setTranslateX(Math.random() * width);
                    svgPath.setTranslateY(0.0);
                    double scale = Math.random() + 0.1;
                    svgPath.setScaleX(scale);
                    svgPath.setScaleY(scale);
                    return;
                }
                svgPath.setTranslateY(translateY + 1.0);
                // TODO: 这里好像存在内存飙升问题？？
                svgPath.setRotate(svgPath.getRotate() + 1.0);
            });
        }

        private void computeFPS(long now) {
            // 距离上一帧经过的时间
            long elapsedTime = now - lastTime;
            long seconds = elapsedTime / 1_000_000_000;
            // 经过了1秒
            if (seconds >= 1L) {
                // 设置FPS（处理数 / 经过时间）
                frameRateText.setText(String.valueOf(handleCount / seconds));
                handleCount = 0;
                // 保存上一秒时间戳
                lastTime = now;
            }
            handleCount++;
        }

    };


    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void init() {
        fpsLayout();
    }

    private void fpsLayout() {
        fpsText.setFont(Font.font(30.0));
        fpsText.setFill(Color.WHITE);
        frameRateText.setFont(Font.font(30.0));
        frameRateText.setFill(Color.WHITE);
        HBox fpsHBox = new HBox(10.0, fpsText, frameRateText);
        fpsHBox.setMaxSize(0.0, 0.0);
        BorderPane.setAlignment(fpsHBox, Pos.TOP_RIGHT);
        root.setTop(fpsHBox);
    }


    public void start(Stage primaryStage) {
        primaryStage.setTitle(getClass().getSimpleName());
        // 透明窗体
        primaryStage.initStyle(StageStyle.TRANSPARENT);
        // 设置最大化
        primaryStage.setMaximized(true);
        // 位于顶层
        primaryStage.setAlwaysOnTop(true);
        primaryStage.setScene(new Scene(root, null));
        primaryStage.show();

        double width = root.getWidth() - 30.0;
        double height = root.getHeight();
        for (int i = 0; i < svgPathCapacity; i++) {
            SVGPath svgPath = svgPathSupplier.get();
            svgPath.setTranslateX(Math.random() * width);
            svgPath.setTranslateY(Math.random() * height);
            double scale = Math.random() + 0.1;
            svgPath.setScaleX(scale);
            svgPath.setScaleY(scale);
            svgPathList.add(svgPath);
        }
        root.setCenter(new Pane(svgPathList.toArray(new SVGPath[0])));
        animationTimer.start();
    }
}
